/**************************************************
 * Figaro.ino
 *
 * Plays "Non più andrai farfallone..." from 
 * from "Le nozze di Figaro"
 *
 * Use right button to start/stop and the
 * slider to increase/decrease music "speed"
 *
 * Created on 19 dicember 2013
 * By Marco & Stefano Ricci <stefano@ricciandco.it>
 ****************************************************/
#include <Esplora.h>

/*
 * Notes frequencies
 */
#define PAUSE   -1
#define DO4    262
#define RE4    294
#define MI4    330
#define FA4    349
#define SOL4   392
#define LA4    440
#define SI4    494
#define DO5    523
#define RE5    587
#define MI5    659

/*
 * Notes durations
 */
#define UNQUARTO      0.25
#define DUEQUARTI     0.50
#define TREQUARTI     0.75
#define QUATTROQUARTI 1.00

typedef struct note_t
{
  int freq;
  double duration;
} note;

note figaro[] = { 
  {SOL4, TREQUARTI}, 
  {SOL4, UNQUARTO},
 
  {MI4, QUATTROQUARTI},
  {SOL4, TREQUARTI},
  {SOL4, UNQUARTO},
  {MI4, QUATTROQUARTI},
  {SOL4, TREQUARTI},
  {SOL4, UNQUARTO},
  
  {FA4, QUATTROQUARTI},
  {RE4, QUATTROQUARTI},
  {PAUSE, QUATTROQUARTI},
  {FA4, TREQUARTI},
  {FA4, UNQUARTO},
  
  {RE4, QUATTROQUARTI},
  {FA4, TREQUARTI},
  {FA4, UNQUARTO},
  {RE4, QUATTROQUARTI},
  {FA4, TREQUARTI},
  {FA4, UNQUARTO}, 
  
  {MI4, QUATTROQUARTI},
  {DO4, QUATTROQUARTI},
  {PAUSE, QUATTROQUARTI},
  {DO4, TREQUARTI},
  {MI4, UNQUARTO},
  
  {SOL4, QUATTROQUARTI},
  {MI4, TREQUARTI},
  {SOL4, UNQUARTO},
  {DO5, QUATTROQUARTI},
  {SOL4, TREQUARTI},
  {DO5, UNQUARTO},
  
  {MI5, QUATTROQUARTI},
  {DO5, QUATTROQUARTI},
  {PAUSE, QUATTROQUARTI},
  {SOL4, TREQUARTI},
  {DO5, UNQUARTO},
  
  {SOL4, QUATTROQUARTI},
  {MI4, TREQUARTI},
  {SOL4, UNQUARTO},
  {FA4, QUATTROQUARTI},
  {RE4, TREQUARTI},
  {SOL4, UNQUARTO},
  
  {MI4, QUATTROQUARTI},
  {MI4, TREQUARTI},
  {MI4, UNQUARTO},
  {MI4, QUATTROQUARTI},
  {DO4, TREQUARTI},
  {MI4, UNQUARTO},
  
  {SOL4, QUATTROQUARTI},
  {MI4, TREQUARTI},
  {SOL4, UNQUARTO},
  {DO5, QUATTROQUARTI},
  {SOL4, TREQUARTI},
  {DO5, UNQUARTO},
  
  {MI5, QUATTROQUARTI},
  {DO5, QUATTROQUARTI},
  {PAUSE, QUATTROQUARTI},
  {SOL4, TREQUARTI},
  {DO5, UNQUARTO},
  
  {SOL4, QUATTROQUARTI},
  {MI4, TREQUARTI},
  {SOL4, UNQUARTO},  
  {FA4, QUATTROQUARTI},
  {RE4, TREQUARTI},
  {SOL4, UNQUARTO}, 

  {DO4, QUATTROQUARTI},
  {DO4, TREQUARTI},
  {DO4, UNQUARTO},  
  {DO4, QUATTROQUARTI},

  {NULL,NULL}
};

int pulse;

boolean started = false;
boolean justStarted = false;

void setup() {
  /*
   * Initialize serial port
   */
  Serial.begin(9600);
}

void loop() {
  
  activeDelay(50);
  
  if (justStarted == true) {
    justStarted = false;
    playMusic();
  }
}

/*
 * Similar to delay(), but allows the program to do something else
 * in the meanwhile. In particular, it calls readSensors().
 * Note 1: it may wait longer than the specified amount, not less;
 * Note 2: beware of data synchronization issues, e.g. if the
 * activeDelay() function alters some variables used by the
 * caller of this function.
 *
 * code from http://arduino.cc/en/Tutorial/EsploraTable
 */
void activeDelay(unsigned long amount) {
  unsigned long at = millis() + amount;
  while (millis() < at) {
    readSensors();
  }
}

/*
 * This function reads the status of the sensors; if it sees that
 * the switch was pressed, toggles the status of the "started" variable.
 * If it's set to true, also the justStarted variable is set to
 * true, so the loop() function above can start playing.
 * This function should be called as often as possible and do as
 * little as possible, because it can be called while another
 * function is running.
 */
void readSensors() {
  static boolean lastStartBtn = HIGH;
  
  boolean startBtn = Esplora.readButton(SWITCH_RIGHT);

  if (startBtn != lastStartBtn) {
    if (startBtn == HIGH) { // button released
      started = !started;
      if (started)
        justStarted = true;    
    }
    
    lastStartBtn = startBtn;
  }
  
  /*
   * setting pulse duration
   */
  int sliderValue = Esplora.readSlider();
  pulse = map(sliderValue, 0, 1023, 200, 2000);
}
 
/*
 * loop on "figaro" array (provided that "started" is true)
 */
void playMusic() {
  
  int i = 0;
  note n = figaro[i];
  
  while (n.freq != NULL) {
    if (!started) break;
    playNote(n.freq, (int)(n.duration*pulse));
    n=figaro[++i];
  }
  /*
   * stop the music at the end
   */
  Esplora.noTone(); 
}

void playNote(int freq, int duration) 
{
  /*
   * log to the serial port
   */
  Serial.print("freq: "),
  Serial.print(freq); 
  Serial.print(" duration: "),
  Serial.println(duration);   
  
  /* 
   * Play the note...
   */
  if (freq == PAUSE) { 
    Esplora.noTone(); 
  } else { 
    Esplora.tone(freq); 
  } 
  /*
   * for the given duration
   */
  activeDelay(duration); 
}
